#include <nds.h>
#include <testMap_bin.h>
#include <testTiles_bin.h>
#include <testPal_bin.h>

//#define DEBUG

#ifdef DEBUG
#include <stdio.h>
#endif

void setupVideoModes()
{

  vramSetMainBanks(
		   VRAM_A_MAIN_BG_0x06000000
		   , VRAM_B_MAIN_BG_0x06020000
		   , VRAM_C_SUB_BG_0x06200000
		   , VRAM_D_MAIN_BG);

  videoSetMode(MODE_0_2D | DISPLAY_BG0_ACTIVE);
  
  #ifndef DEBUG
  videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE);
  #else
  videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE);
  consoleInitDefault((u16*)SCREEN_BASE_BLOCK_SUB(31), (u16*)CHAR_BASE_BLOCK_SUB(0), 16);

  #endif

  lcdSwap();
}

void setupBackgrounds()
{

  BG0_CR = BG_32x64 | BG_COLOR_256 | BG_TILE_BASE(1) | BG_MAP_BASE(0) | BG_PRIORITY(1) | BG_WRAP_ON;

#ifndef DEBUG
  SUB_BG0_CR = BG_32x64 | BG_COLOR_256 | BG_TILE_BASE(1) | BG_MAP_BASE(0) | BG_PRIORITY(1)| BG_WRAP_ON;
  SUB_BG0_X0 = 0;
  SUB_BG0_Y0 = -128; 
#endif

  BG0_X0 = 0;
  BG0_Y0 = 64; 


  
}

int main(void)
{
 
  /*
    Setup video system
  */
  setupVideoModes();

  /*
    Init backgrounds
  */
  setupBackgrounds();


  u8* mainBG0TileMemory = (u8*)BG_TILE_RAM(1);
  u16* mainBG0MapMemory = (u16*)BG_MAP_RAM(0);

 

  u16 screenSizeInTile = 32*32;


  memcpy((void*)BG_PALETTE, testPal_bin, testPal_bin_size);
  memcpy((void*)mainBG0MapMemory, testMap_bin, screenSizeInTile*2*2);
  memcpy((void*)mainBG0TileMemory, testTiles_bin,  testTiles_bin_size);

  #ifndef DEBUG
  u8* subBG0TileMemory = (u8*)BG_TILE_RAM_SUB(1);
  u16* subBG0MapMemory = (u16*)BG_MAP_RAM_SUB(0);
  memcpy((void*)BG_PALETTE_SUB, testPal_bin, testPal_bin_size);
  memcpy((void*)subBG0MapMemory, testMap_bin, screenSizeInTile*2*2);
  memcpy((void*)subBG0TileMemory, testTiles_bin,  testTiles_bin_size);
  #endif

  irqInit();
  irqEnable(IRQ_VBLANK);

  u16 scrollx=0;
  int scrollyMain=64;

  int scrollySub=-128;

  //scrolling speed :P
  u16 scrollYSpeed = 2;

  //used to know when to dynamically load a new row of the map (ie each tile we scrolled a whole row of tiles out of the screen)
  u16 updateMapData = 8;

  #ifdef DEBUG
  SUB_BG0_CR = BG_MAP_BASE(31);
  BG_PALETTE_SUB[255] = RGB15(15,25,10);
  #endif

  //Pointer on the "input" map data's current screen (when updating lines, we start from the last, this points to the first)
  u16* mainScreenCurrentMapDataBase =(u16*)(testMap_bin) + screenSizeInTile*2;

  //Pointer on the current line to copy from the current screen
  u16* mainScreenCurrentMapData = (u16*)(testMap_bin) + screenSizeInTile*2 + (screenSizeInTile-32);

  //Pointer on the line to update in vram
  u16* mainBG0MapMemoryLastLine = mainBG0MapMemory + screenSizeInTile - 32;


  //Pointer on the "input" map data's current screen (when updating lines, we start from the last, this points to the first)
  u16* subScreenCurrentMapDataBase =(u16*)(testMap_bin) + screenSizeInTile*2;

  //Pointer on the current line to copy from the current screen
  u16* subScreenCurrentMapData = (u16*)(testMap_bin) + screenSizeInTile*2 + (screenSizeInTile-32);

  //Pointer on the line to update in vram
  u16* subBG0MapMemoryLastLine = subBG0MapMemory + screenSizeInTile - 32;
  

  while(1)
    {
      swiWaitForVBlank();

      // read the button states
      scanKeys();
      
      int pressed = keysDown();	// buttons pressed this loop
      int held = keysHeld();	// buttons currently held
      
      //
      if ( pressed & KEY_UP ||held& KEY_UP )
	{
	  //update the scrolling
	  scrollyMain-=scrollYSpeed;
	  scrollySub-=scrollYSpeed;

	  //update the update counter
	  updateMapData-=scrollYSpeed;

	  //we need to update the map data
	  if(updateMapData==0)
	    {
	      //copy a whole line of tiles
	      memcpy((void*)mainBG0MapMemoryLastLine, mainScreenCurrentMapData, 32*2);

	      memcpy((void*)subBG0MapMemoryLastLine, subScreenCurrentMapData, 32*2);

	      //if we have just finished to read a whole screen
	      if(mainScreenCurrentMapData == mainScreenCurrentMapDataBase)
		{
		  //update the base to point to the next
		  mainScreenCurrentMapDataBase += screenSizeInTile;
		  
		  //if it was the last, point to the first one
		  if(mainScreenCurrentMapDataBase == (u16*)(testMap_bin + testMap_bin_size))
		    {
		      mainScreenCurrentMapDataBase=(u16*)(testMap_bin);
		    }

		  //we start by reading the last line of the new screen
		  mainScreenCurrentMapData = mainScreenCurrentMapDataBase + (screenSizeInTile-32);
		}
	      else
		{
		  //go to the next line (up)
		  mainScreenCurrentMapData -= 32;
		}

	      //if we have just finished to read a whole screen
	      if(subScreenCurrentMapData == subScreenCurrentMapDataBase)
		{
		  //update the base to point to the next
		  subScreenCurrentMapDataBase += screenSizeInTile;
		  
		  //if it was the last, point to the first one
		  if(subScreenCurrentMapDataBase == (u16*)(testMap_bin + testMap_bin_size))
		    {
		      subScreenCurrentMapDataBase=(u16*)(testMap_bin);
		    }

		  //we start by reading the last line of the new screen
		  subScreenCurrentMapData = subScreenCurrentMapDataBase + (screenSizeInTile-32);
		}
	      else
		{
		  //go to the next line (up)
		  subScreenCurrentMapData -= 32;
		}



	      //wrapping for the line to update
	      if(mainBG0MapMemoryLastLine == mainBG0MapMemory)
		{
		  mainBG0MapMemoryLastLine=mainBG0MapMemory + (screenSizeInTile*2) - 32;
		}
	      else
		{
		  //prepare to update the next line (up)
		  mainBG0MapMemoryLastLine -= 32;
		}

	      //wrapping for the line to update
	      if(subBG0MapMemoryLastLine == subBG0MapMemory)
		{
		  subBG0MapMemoryLastLine=subBG0MapMemory + (screenSizeInTile*2) - 32;
		}
	      else
		{
		  //prepare to update the next line (up)
		  subBG0MapMemoryLastLine -= 32;
		}


	      //restart the counter
	      updateMapData=8;
	    }

	  //scroll the screen
	  BG0_Y0 = scrollyMain;  
	  SUB_BG0_Y0 = scrollySub; 
	}
      if ( pressed & KEY_DOWN ||held& KEY_DOWN)
	{
	  scrollyMain+=scrollYSpeed;
	  BG0_Y0 = scrollyMain;  //SUB_BG0_Y0 = scrollyMain; 
	} 
      if ( pressed & KEY_LEFT ||held& KEY_LEFT)
	{
	} 
      if ( pressed & KEY_RIGHT ||held& KEY_RIGHT)
	{
	}

    }
}

